package cn.ddiancan.xddcloud.psc.permission.service;

import cn.ddiancan.xddcloud.common.context.RequestContext;
import cn.ddiancan.xddcloud.common.context.XddCloudContextUtils;
import cn.ddiancan.xddcloud.common.entity.CommonResult;
import cn.ddiancan.xddcloud.common.entity.PermissionVO;
import cn.ddiancan.xddcloud.common.entity.UserVO;
import cn.ddiancan.xddcloud.psc.permission.annotation.UserOperation;
import cn.ddiancan.xddcloud.psc.permission.annotation.UserResource;
import cn.ddiancan.xddcloud.psc.permission.feign.PermissionRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;

@Slf4j
@Service
public class PermissionService {

    private static final String CLASS_PATH_PREFIX = "classpath*:";

    @Value("${xddcloud.user.permission.scan-package:cn.ddiancan.**.**}")
    private String scanPackage;

    @Autowired
    private PermissionRemoteService permissionRemoteService;

    /**
     * 扫描包下所有的权限点信息
     *
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public CommonResult<Integer> scanPermission() {
        try {
            String basePackage = CLASS_PATH_PREFIX + scanPackage;
            String replacePath = basePackage.replace(".", "/") + ".class";
            PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            Resource[] resources = resourcePatternResolver.getResources(replacePath);
            List<PermissionVO> permissionVOList = new ArrayList<>();
            for (Resource resource : resources) {
                if (resource.isReadable()) {
                    MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
                    MergedAnnotation<UserResource> userResourceMergedAnnotation =
                        metadataReader.getAnnotationMetadata().getAnnotations().get(UserResource.class);
                    getMethodAnnotations(userResourceMergedAnnotation, metadataReader, permissionVOList);
                }
            }
            if (!CollectionUtils.isEmpty(permissionVOList)) {
                return permissionRemoteService.sysncPermission(permissionVOList);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return CommonResult.failed();
    }

    /**
     * 处理数据
     *
     * @param userResourceMergedAnnotation
     * @param metadataReader
     */
    private static void getMethodAnnotations(MergedAnnotation<UserResource> userResourceMergedAnnotation,
        MetadataReader metadataReader, List<PermissionVO> permissionVOList) {
        if (userResourceMergedAnnotation.isPresent()) {
            UserResource userResource = userResourceMergedAnnotation.synthesize();
            Date date = new Date();
            UserVO ddcUser = RequestContext.getCurrentContextUser();
            Set<MethodMetadata> declaredMethods = metadataReader.getAnnotationMetadata().getDeclaredMethods();
            declaredMethods.forEach(method -> {
                MergedAnnotation<UserOperation> userOperationMergedAnnotation =
                    method.getAnnotations().get(UserOperation.class);
                if (userOperationMergedAnnotation.isPresent()) {
                    UserOperation userOperation = userOperationMergedAnnotation.synthesize();
                    PermissionVO permissionVO = new PermissionVO();
                    permissionVO.setResourceCode(userResource.code());
                    permissionVO.setResourceDescription(userResource.desc());
                    permissionVO.setOperationCode(userOperation.code());
                    permissionVO.setOperationDescription(userOperation.desc());
                    permissionVO.setApplciationName(XddCloudContextUtils.getApplication());
                    permissionVO.setCreateDate(date);
                    permissionVO.setLastUpdateDate(date);
                    permissionVO.setLastUpdateBy(Objects.nonNull(ddcUser) ? ddcUser.getLastUpdateBy() : "1");
                    permissionVO.setCreatedBy(Objects.nonNull(ddcUser) ? ddcUser.getCreatedBy() : "1");
                    permissionVOList.add(permissionVO);
                }
            });
        }
    }
}
